{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"../../assets/640.webp\" width=\"60%\">\n",
    "\n",
    "# FastAPI 干啥的？\n",
    "\n",
    "FastAPI 是用来构建 API 服务的一个高性能框架。\n",
    "\n",
    "# 为什么选择 FastAPI ?\n",
    "\n",
    "FastAPI 是一个现代、高性能 web 框架，用于构建 APIs，基于 Python 3.6 及以上版本。\n",
    "\n",
    "- 最大特点：快！性能极高，可与 NodeJS, Go 媲美。\n",
    "- 基于 Starlette 和 Pydantic，是 FastAPI 如此高性能的重要原因。\n",
    "- 具备代码复用性高，容易上手，健壮性强的优点。\n",
    "- 方便的 API 调试，生成 API 文档，直接能够做到调试自己构建的 API，这在实际应用中，价值凸显。\n",
    "\n",
    "FastAPI 这么强悍，有必要研究和使用，因为无论做开发，还是做算法，API 服务真的太重要，太重要，尤其是大厂，离不开 API 接口。\n",
    "\n",
    "# Pydantic 做类型强制检查\n",
    "\n",
    "FastAPI 基于 `Pydantic` ，`Pydantic` 主要用来做类型强制检查。参数赋值，不符合类型要求，就会抛出异常。\n",
    "\n",
    "对于 API 服务，支持类型检查非常有用，会让服务更加健壮，也会加快开发速度，因为开发者再也不用自己写一行一行的做类型检查。\n",
    "\n",
    "首先\n",
    "> pip install pydantic\n",
    "\n",
    "然后，使用 `Pydantic` 做强制类型检查。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "from typing import List\n",
    "from pydantic import BaseModel, ValidationError\n",
    "\n",
    "\n",
    "class User(BaseModel):\n",
    "    id: int\n",
    "    name = 'jack guo'\n",
    "    signup_timestamp: datetime = None\n",
    "    friends: List[int] = []"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "观察到：\n",
    "\n",
    "- id 要求必须为 int\n",
    "- name 要求必须为 str, 且有默认值\n",
    "- signup_timestamp 要求为 datetime, 默认值为 None\n",
    "- friends 要求为 List，元素类型要求 int, 默认值为 []\n",
    "\n",
    "使用 User 类："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\n",
      "  {\n",
      "    \"loc\": [\n",
      "      \"id\"\n",
      "    ],\n",
      "    \"msg\": \"field required\",\n",
      "    \"type\": \"value_error.missing\"\n",
      "  },\n",
      "  {\n",
      "    \"loc\": [\n",
      "      \"signup_timestamp\"\n",
      "    ],\n",
      "    \"msg\": \"invalid datetime format\",\n",
      "    \"type\": \"value_error.datetime\"\n",
      "  },\n",
      "  {\n",
      "    \"loc\": [\n",
      "      \"friends\",\n",
      "      3\n",
      "    ],\n",
      "    \"msg\": \"value is not a valid integer\",\n",
      "    \"type\": \"type_error.integer\"\n",
      "  }\n",
      "]\n"
     ]
    }
   ],
   "source": [
    "try:\n",
    "    User(signup_timestamp='not datetime',friends=[1,2,3,'not number'])\n",
    "except ValidationError as e:\n",
    "    # 打印验证信息\n",
    "    print(e.json())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 快速上手 FastAPI\n",
    "\n",
    "这是一个入门 demo, 构建以下三个路由：\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from fastapi import FastAPI\n",
    "from pydantic import BaseModel\n",
    "\n",
    "app = FastAPI()\n",
    "\n",
    "\n",
    "class User(BaseModel):\n",
    "    id: int\n",
    "    name: str\n",
    "    friends: list\n",
    "\n",
    "\n",
    "@app.get(\"/\")\n",
    "def index():\n",
    "    return {\"admin\": \"welcome to FastAPI\"}\n",
    "\n",
    "\n",
    "@app.get(\"/users/{user_id}\")\n",
    "def read_user(user_id: int, name: str = None):\n",
    "    return {\"user_id\": user_id, \"name\": name}\n",
    "\n",
    "\n",
    "@app.put(\"/users/{user_id}\")\n",
    "def update_user(user_id: int, user: User):\n",
    "    return {\"user_name\": user.name, \"user_id\": user_id}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 将上述代码保存为 `main.py`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%save -r main.py 3  # 保存单元格序号为3 的内容到文件中"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 安装与构建服务相关的框架 `uvicorn`\n",
    "\n",
    "```\n",
    "pip3 install uvicorn  \n",
    "uvicorn --help\n",
    "```\n",
    "\n",
    "## 安装完成后，后台执行：\n",
    "\n",
    "```\n",
    "uvicorn main:app --reload\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!uvicorn main:app --reload"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "启动服务，显示如下：\n",
    "\n",
    "<img src=\"../../assets/fastapi1.webp\" width=\"60%\">\n",
    "\n",
    "## 访问\n",
    "\n",
    "- 打开客户端，输入：<http://localhost:8000>，回车：\n",
    "\n",
    "<img src=\"../../assets/fastapi2.webp\" width=\"60%\">\n",
    "\n",
    "- 输入请求：：<http://localhost:8000/users/5>，回车，看到前台数据，非常容易的就能传递到 controller 层，方便。\n",
    "\n",
    "<img src=\"../../assets/fastapi3.webp\" width=\"60%\">\n",
    "\n",
    "- 输入请求：<http://localhost:8000/docs>，回车：，看到 API 文档界面\n",
    "\n",
    "<img src=\"../../assets/fastapi4.webp\" width=\"60%\">\n",
    "\n",
    "- 点开第二个 get 请求，然后点击 Try it out 后，便可以进行接口调试。非常方便！\n",
    "\n",
    "<img src=\"../../assets/fastapi5.webp\" width=\"60%\">\n",
    "\n",
    "输入user_id， name 后，点击 Execute，执行成功。如果 user_id 输入非数值型，点击 Execute 后，红框闪动一下，不会执行，直到输入正确为止。\n",
    "\n",
    "<img src=\"../../assets/fastapi6.webp\" width=\"60%\">\n",
    "\n",
    "输入user_id， name 后，点击 Execute，\n",
    "\n",
    "能看到结果，包括请求的 URL\n",
    "\n",
    "<img src=\"../../assets/fastapi7.webp\" width=\"60%\">\n",
    "\n",
    "也能看到，服务器响应前端，返回的结果：\n",
    "\n",
    "<img src=\"../../assets/fastapi8.webp\" width=\"60%\">\n",
    "\n",
    "FastAPI 基于以上这些强大的优点，相信在实际开发 API 服务时，会很敏捷。\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
